#pragma once

#include <csetjmp>
#include <iterator>
#include <vector>
#include <assert.h>
#include <string>

using std::vector;
using std::string;
/// @code
/// +-------------------+------------------+------------------+
/// | prependable bytes |  readable bytes  |  writable bytes  |
/// |                   |     (CONTENT)    |                  |
/// +-------------------+------------------+------------------+
/// |                   |                  |                  |
/// 0      <=      readerIndex   <=   writerIndex    <=     size
/// @endcode


class Buffer
{
public:
    static const size_t kCheapPrepend = 8; //头部预留
    static const size_t kInitialSize = 1024; //预分配1k

    Buffer(size_t size = kInitialSize);
    ~Buffer()
    {

    }
    Buffer(const Buffer &) = delete;
    Buffer &operator=(const Buffer &) = delete;

    ssize_t readFd(int fd);


    size_t readableBytes() const 
    {
        return _writerIndex - _readerIndex;
    }

    size_t writableBytes() const 
    {
        return _buffer.size() - _writerIndex;
    }

    size_t prependableBytes() const 
    {
        return _readerIndex;
    }

    const char* peek() const  // 可读地址
    {
        return begin() +  _readerIndex;
    }

    void hasWritten(size_t len)
    {
        assert(len <= writableBytes());
        _writerIndex += len;
    }

    char *beginWrite() 
    {
        return begin() + _writerIndex;
    }
    const char* beginWrite() const
    {
        return begin() + _writerIndex;
    }

    void retrieve(size_t len)
    {
        assert(len <= readableBytes());
        if(len < readableBytes())
        {
            _readerIndex += len;
        }
        else
        {
            retrieveAll();
        }
    }

    void retrieveAll()
    {
        _readerIndex = kCheapPrepend;
        _writerIndex = kCheapPrepend;
    }

    string retrieveAllAsString()
    {
        return retrieveAsString(readableBytes());
    }

    string retrieveAsString(size_t len)
    {
        assert(len <= readableBytes());
        string res(peek(), len);
        retrieve(len);
        return res;
    }
    void append(const char* data, size_t len);
private:
    vector<char> _buffer; 
    size_t _readerIndex;
    size_t _writerIndex;

    char* begin() { return &*_buffer.begin(); }
    const char* begin() const  { return &*_buffer.begin(); }
    void ensureWriteBytes(size_t len);
    void makeSpace(size_t len);
};

